package com.fastloan.mgt.verify.util;

import com.alibaba.fastjson.JSON;
import com.fastloan.mgt.verify.enums.ApiStore;
import com.fastloan.mgt.verify.model.ApiResult;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

/**
 * @author yanwe
 *         createTime 2017-12-2017/12/8 10:45
 */
public class ApiUtil {

    private static OkHttpClient okHttpClient = new OkHttpClient.Builder()
            .connectTimeout(60, TimeUnit.SECONDS)
            .readTimeout(60, TimeUnit.SECONDS)
            .build();

    private static final MediaType JSONType = MediaType.parse("application/json; charset=utf-8");

    private static final Logger logger = LoggerFactory.getLogger(ApiUtil.class);

    public static Integer ERROR_CODE = 500;

    public static Integer SUCCESS_CODE = 200;

    public static Integer KX_SUCCESS_CODE = 0;

    public static ApiResult sendGetSync(GetParam getParam, ApiStore apiStore) {
        return sendGetSync(getParam,apiStore.getUrl());
    }

    public static ApiResult sendGetSync(GetParam getParam, String url) {
        return sendGet(getParam, url, null, null);
    }

    public static void sendGetAsync(GetParam getParam, ApiStore apiStore
            , Consumer<ApiCall> onFailure, BiConsumer<ApiCall, ApiResult> onResponse) {
        sendGetAsync(getParam,apiStore.getUrl(),onFailure,onResponse);
    }

    public static void sendGetAsync(GetParam getParam, String url
            , Consumer<ApiCall> onFailure, BiConsumer<ApiCall, ApiResult> onResponse) {
        sendGet(getParam, url, onFailure, onResponse);
    }

    public static ApiResult sendPostSync(RequestBody requestBody, ApiStore apiStore) {
        return sendPostSync(requestBody,apiStore.getUrl());
    }

    public static ApiResult sendPostSync(RequestBody requestBody, String url) {
        return sendPost(requestBody, url, null, null);
    }

    public static void sendPostAsync(RequestBody requestBody, ApiStore apiStore
            , Consumer<ApiCall> onFailure, BiConsumer<ApiCall, ApiResult> onResponse) {
        sendPostAsync(requestBody, apiStore.getUrl(), onFailure, onResponse);
    }
    public static void sendPostAsync(RequestBody requestBody, String url
            , Consumer<ApiCall> onFailure, BiConsumer<ApiCall, ApiResult> onResponse) {
        sendPost(requestBody, url, onFailure, onResponse);
    }

    public static ApiResult sendJsonSync(String json, ApiStore apiStore) {
        return sendJsonSync(json, apiStore.getUrl());
    }

    public static ApiResult sendJsonSync(String json, String url) {
        RequestBody requestBody = RequestBody.create(JSONType, json);
        return sendPost(requestBody, url, null, null);
    }

    public static void sendJsonAsync(String json, ApiStore apiStore
            , Consumer<ApiCall> onFailure, BiConsumer<ApiCall, ApiResult> onResponse) {
        sendJsonAsync(json, apiStore.getUrl(), onFailure, onResponse);
    }

    public static void sendJsonAsync(String json, String url
            , Consumer<ApiCall> onFailure, BiConsumer<ApiCall, ApiResult> onResponse) {
        RequestBody requestBody = RequestBody.create(JSONType, json);
        sendPost(requestBody, url, onFailure, onResponse);
    }

    private static ApiResult sendGet(GetParam getParam, String url
            , Consumer<ApiCall> onFailure, BiConsumer<ApiCall, ApiResult> onResponse) {
        final Request request = new Request.Builder()
                .url(url + getParam.toUrl())
                .get()
                .build();
        if (onFailure == null || onResponse == null) {
            return sendSync(request);
        } else {
            sendAsync(request, onFailure, onResponse);
        }
        return null;
    }

    private static ApiResult sendPost(RequestBody requestBody, String url
            , Consumer<ApiCall> onFailure, BiConsumer<ApiCall, ApiResult> onResponse) {
        final Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        if (onFailure == null || onResponse == null) {
            return sendSync(request);
        } else {
            sendAsync(request, onFailure, onResponse);
        }
        return null;
    }


    private static ApiResult sendSync(Request request) {
        Call call = okHttpClient.newCall(request);
        String url = request.url().url().toString();
        try {
            Response response = call.execute();
            ResponseBody responseBody = response.body();
            if (responseBody == null) {
                String errorMsg = logError(url, "ResponseBody is Null");
                return ApiResult.ApiResultBuilder.anApiResult().withRet(ERROR_CODE)
                        .withMsg(errorMsg).build();
            }
            if (!response.isSuccessful()) {
                String errorMsg = logError(url, "code:" + response.code()
                        + ",错误原因:" + response.message()+",错误信息:"
                        + responseBody.string());
                return ApiResult.ApiResultBuilder.anApiResult().withRet(ERROR_CODE).withMsg(errorMsg).build();
            }
            String responseBodyStr = responseBody.string();
            logSuccess(url, responseBodyStr);
            return processResult(responseBodyStr);
        } catch (IOException e) {
            String errorMsg = logError(url, e.getMessage());
            e.printStackTrace();
            return ApiResult.ApiResultBuilder.anApiResult().withRet(ERROR_CODE).withMsg(errorMsg).build();
        }
    }

    private static void sendAsync(Request request, Consumer<ApiCall> onFailure
            , BiConsumer<ApiCall, ApiResult> onResponse) {
        Call call = okHttpClient.newCall(request);
        String url = request.url().url().toString();
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                ApiCall apiCall = ApiCall.ApiCallBuilder.anApiCall()
                        .withCall(call).withCallback(this).build();
                onFailure.accept(apiCall);
                e.printStackTrace();
                logger.error(e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                ApiCall apiCall = ApiCall.ApiCallBuilder.anApiCall()
                        .withCall(call).withCallback(this).build();
                ResponseBody responseBody = response.body();
                if (responseBody == null) {
                    String errorMsg = logError(url, "ResponseBody is Null");
                    onResponse.accept(apiCall, ApiResult.ApiResultBuilder.anApiResult().withRet(ERROR_CODE)
                            .withMsg(errorMsg).build());
                    return;
                }
                if (!response.isSuccessful()) {
                    String errorMsg = logError(url, "code:" + response.code()
                            + ",错误原因:" + response.message()+",错误信息:"
                            + responseBody.string());
                    onResponse.accept(apiCall, ApiResult.ApiResultBuilder.anApiResult()
                            .withRet(ERROR_CODE).withMsg(errorMsg).build());
                    return;
                }
                String responseBodyStr = responseBody.string();
                logSuccess(url, responseBodyStr);
                onResponse.accept(apiCall, processResult(responseBodyStr));
            }
        });
    }

    private static ApiResult processResult(String responseBodyStr) {
        ApiResult apiResult = null;
        try {
            apiResult = JSON.parseObject(responseBodyStr, ApiResult.class);
        } catch (Exception e) {
            logger.debug("非正常格式数据:"+responseBodyStr);
        }
        if (apiResult == null) {
            apiResult = new ApiResult();
            apiResult.setMsg("数据请求成功");
            apiResult.setRet(SUCCESS_CODE);
            apiResult.setData(responseBodyStr);
        }
        return apiResult;
    }

    private static String logSuccess(String url, String responseBodyStr) {
        String title = "API请求成功!";
        String urlStr = "URL:" + url;
        String response = "Response:" + responseBodyStr;
        logger.debug(title);
        logger.debug(urlStr);
        logger.debug(response);
        return title + urlStr + "," + response;
    }

    private static String logError(String url, String errorMsg) {
        String title = "API请求错误!";
        String urlStr = "URL:" + url;
        String errorMsgStr = "ErrorMsg:" + errorMsg;
        logger.debug(title);
        logger.debug(urlStr);
        logger.debug(errorMsgStr);
        return title + urlStr + "," + errorMsgStr;
    }
}
